﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Threading;
using OBID;

namespace ISOHostSample
{
    class RFIDReaderClass : FeIscListener
    {
        FedmIscReader fedm;

        byte[] CustomerIDArray = new byte[4];

        public bool running;

        string TransponderSerialNumber;
        byte SerialNumberLen;

        uint persistenceResetTime = 0;
        Boolean Prepared = false;

        //declaration from delegatetyp
        public delegate void DelegateTagChanged(string[] serialNumber, byte[] tagType);
        public delegate void DelegateLastError(string err);
        public delegate void DelegateNoTag(int readerStatus);
        public delegate void DelegateOnSendProtocol(string sendprotocol);
        public delegate void DelegateOnReceiveProtocol(string receiveprotocol);
        Thread MyThread;

        Thread MyThreadGetID;

        public string GetReaderID()
        {

            return fedm.GetPortPara("Device-ID");
        }

        public string GetCustomerID()
        {
            CustomerIDArray = new byte[4];
            Prepared = false;
            running = true;

           // System.Diagnostics.Stopwatch stopwatch = System.Diagnostics.Stopwatch.StartNew();
            while (running || !Prepared)
            {
                Application.DoEvents();
                //some other processing to do STILL POSSIBLE
                //if (stopwatch.ElapsedMilliseconds >= 100)
                //{
                //    break;
                //}
                //Thread.Sleep(1); //so processor can rest for a while
            }

            Read();
            return Helperclass.ByteArrayToString(CustomerIDArray);
        }

        public Boolean InitializeReader()
        {
            string id = "";
             MyThread = new Thread(new ThreadStart(DetectThread));
             //MyThreadGetID = new Thread(new ThreadStart(GetCustomerID));

           //### USB port Connecten - 
            try
            {
                fedm = new FedmIscReader();
                fedm.ConnectUSB(0);

                //declaration from Thread
                

                fedm.SetTableSize(FedmIscReaderConst.ISO_TABLE, 128);
            }
            catch (FePortDriverException ex)
            {
                MessageBox.Show(ex.ToString(), "Error");
            }


            if (fedm.Connected == true)
            {
                //### Liest die gesamte Leserkonfiguration aus.
                try
                {
                    fedm.ReadCompleteConfiguration(false);
                }
                catch (Exception ex)
                {
                    MessageBox.Show(ex.ToString(), "Error");
                }

                // set Persistence Reset Time in Reader Configuration to zero
                // this speeds up inventory cycles
                int back = OBID.Fedm.ERROR_UNSUPPORTED_NAMESPACE;

                //### Testet ob ein Parametername vom  eingestellten Lesertyp unterstützt wird
                try
                {
                    back = fedm.TestConfigPara(OBID.ReaderConfig.Transponder.PersistenceReset.Antenna.No1.PersistenceResetTime);
                }
                catch (Exception ex)
                { // ignore Exception
                }
                // if reader supports this parameter, set it !
                if (0 == back)
                {
                    try
                    {
                        back = fedm.GetConfigPara(OBID.ReaderConfig.Transponder.PersistenceReset.Antenna.No1.PersistenceResetTime, out persistenceResetTime, false);
                        back = fedm.SetConfigPara(OBID.ReaderConfig.Transponder.PersistenceReset.Antenna.No1.PersistenceResetTime, (uint)0, false);
                        if (back == 1) // return value 1 indicates modified parameter
                            back = fedm.ApplyConfiguration(false);
                    }
                    catch (Exception ex)
                    {
                        MessageBox.Show(ex.ToString());
                    }
                }
            }


            if (fedm.Connected == true)
            {
                //Registry from Events send and receive
                fedm.AddEventListener(this, FeIscListenerConst.SEND_STRING_EVENT);
                fedm.AddEventListener(this, FeIscListenerConst.RECEIVE_STRING_EVENT);

                //Thread starten in Background
                running = false;
                MyThread.IsBackground = true;
                MyThread.Start();
               

            }
            else
            {
                MessageBox.Show("Not Connected");
            }

            return true;
        }

        //Construktor, Reader Verbinden, Eventhandler, Threat
        public RFIDReaderClass()
        {
            InitializeReader();
        }

        private void PrepareTransponder()
        {
            int selRow;
            int mode;
            byte bTagType;

            selRow = 0;
            // get Tag Type
            fedm.GetTableData(selRow, FedmIscReaderConst.ISO_TABLE, FedmIscReaderConst.DATA_TRTYPE, out bTagType);

            mode = Konstanten.mode;

            //seriennumemr haben wir bereits als globale variable
            SerialNumberLen = Convert.ToByte(TransponderSerialNumber.Length / 2);
            try
            {
                fedm.SetData(FedmIscReaderID.FEDM_ISC_TMP_B0_REQ_UID, TransponderSerialNumber); // prepare for 0xB0 command
                if (bTagType == FedmIscReaderConst.TR_TYPE_ISO14443A ||
                bTagType == FedmIscReaderConst.TR_TYPE_ISO14443B)
                {
                    fedm.SetData(FedmIscReaderID.FEDM_ISC_TMP_B2_REQ_UID, TransponderSerialNumber); // prepare for 0xB2 command
                }
            }
            catch (System.Exception ex)
            {
                MessageBox.Show(ex.ToString(), "Error");
                return;
            }
            return;
        }


        /**************************************END************************************************/

        /*********************************Methode from interface FeIscListener**********************************************/

        public void OnReceiveProtocol(FedmIscReader reader, byte[] receiveProtocol)
        {
        }

        public void OnReceiveProtocol(FedmIscReader reader, String receiveProtocol)
        {
            //IAsyncResult result;
            //DelegateOnReceiveProtocol ReceiveProtocolMethod = new DelegateOnReceiveProtocol(DisplayReceiveProtocol);
            //result = (IAsyncResult)Invoke(ReceiveProtocolMethod, receiveProtocol);

        }

        public void OnSendProtocol(FedmIscReader reader, byte[] sendProtocol)
        {
        }

        public void OnSendProtocol(FedmIscReader reader, String sendProtocol)
        {
            //IAsyncResult result;
            //DelegateOnSendProtocol SendProtocolMethod = new DelegateOnSendProtocol(DisplaySendProtocol);
            //result = (IAsyncResult)Invoke(SendProtocolMethod, sendProtocol);
        }

        /************************************************************END********************************************************/
        /*******************Methode to show asynchrone Result in GUI****************/

        //Show message error                                                      
        public void LastError(string err)
        {
            //this.buttonRun.Text = "R&un";
            MessageBox.Show( err, "Error");
        }

        //Clear tag list
        public void ClearList(int readerStatus)
        {
            this.TransponderSerialNumber = "0000";
           
        }

        //Show multiple TranspondersID                                           
        public void TagChanged(string[] serialNumber, byte[] tagType)
        {


            if (running)
            {
                if (serialNumber.Length > 1)
                {
                    this.TransponderSerialNumber = "0000";

                    //WriteGui.Set_lb_TagScanResult("Bitte nur einen Transponder vor den RFID-Reader halten");
                }
                else
                {
                    //Ausreichend da nur eine seriennumer - Prüfe ob wirklich in 0
                    this.TransponderSerialNumber = serialNumber[0];
                    running = false;
                    PrepareTransponder();
                    Prepared = true;
                }

            }
        }

        /****************************************END*********************************/

        // methode to execute the thread 
        public void DetectThread()
        {
            int readerStatus = 0;
            string[] serialNumber;
            byte[] tagType;

            //declaration from delegateobject 
            DelegateTagChanged TagChangedMethod = new DelegateTagChanged(TagChanged);
            DelegateLastError LastErrorMethod = new DelegateLastError(LastError);
            DelegateNoTag NoTagMethod = new DelegateNoTag(ClearList);

            object[] obj1 = new object[2];
            object obj2 = null;
            IAsyncResult result;

            while (true)
            {
                if (running == true)
                {
                    fedm.SetData(FedmIscReaderID.FEDM_ISC_TMP_B0_CMD, 0x01);
                    fedm.SetData(FedmIscReaderID.FEDM_ISC_TMP_B0_MODE, 0x00);
                    try
                    {
                        fedm.ResetTable(FedmIscReaderConst.ISO_TABLE);
                        fedm.SendProtocol(0x69); // RFReset
                        readerStatus = fedm.SendProtocol(0xB0); // ISOCmd
                        if (readerStatus != 0 && readerStatus != 0x94)
                        {
                            //obj2 = readerStatus;
                            NoTagMethod(readerStatus);
                            //result = BeginInvoke(NoTagMethod, obj2);
                            //EndInvoke(result);
                            continue;
                        }

                        while (fedm.GetLastStatus() == 0x94) // more flag set?
                        {
                            fedm.SetData(FedmIscReaderID.FEDM_ISC_TMP_B0_MODE_MORE, 0x01);
                            fedm.SendProtocol(0xB0);
                        }
                        //new dimensiion from array serialNumber,tagtype,SeNumbLength
                        serialNumber = new string[fedm.GetTableLength(FedmIscReaderConst.ISO_TABLE)];
                        tagType = new byte[fedm.GetTableLength(FedmIscReaderConst.ISO_TABLE)];

                        if (fedm.GetTableLength(FedmIscReaderConst.ISO_TABLE) <= 0)
                            continue;

                        int i;
                        for (i = 0; i < fedm.GetTableLength(FedmIscReaderConst.ISO_TABLE); i++)
                        {
                            fedm.GetTableData(i, FedmIscReaderConst.ISO_TABLE, FedmIscReaderConst.DATA_SNR, out serialNumber[i]);
                            fedm.GetTableData(i, FedmIscReaderConst.ISO_TABLE, FedmIscReaderConst.DATA_TRTYPE, out tagType[i]);
                            // check, wether UHF tags are available in list
                        }
                        //obj1[0] = serialNumber;
                        TagChangedMethod(serialNumber,null);
                        //asynchrone result senden
                        //result = BeginInvoke(TagChangedMethod, obj1);
                        //EndInvoke(result);

                    }
                    catch (Exception ex)
                    {
                        //obj2 = ex.ToString();
                        //asynchrone result senden
                        LastErrorMethod(ex.ToString());
                        //result = BeginInvoke(LastErrorMethod, obj2);
                        //EndInvoke(result);
                        running = false;
                    }
                }
            }
        }

        private string DetectTag()
        {
            return " ";

            //int readerStatus = 0;
            //string[] serialNumber;
            //byte[] tagType;

            ////declaration from delegateobject 
            //DelegateTagChanged TagChangedMethod = new DelegateTagChanged(TagChanged);
            //DelegateLastError LastErrorMethod = new DelegateLastError(LastError);
            //DelegateNoTag NoTagMethod = new DelegateNoTag(ClearList);

            //object[] obj1 = new object[2];
            //object obj2 = null;
            //IAsyncResult result;


            ////vorher schleife
            //fedm.SetData(FedmIscReaderID.FEDM_ISC_TMP_B0_CMD, 0x01);
            //fedm.SetData(FedmIscReaderID.FEDM_ISC_TMP_B0_MODE, 0x00);
            //try
            //{
            //    fedm.ResetTable(FedmIscReaderConst.ISO_TABLE);
            //    fedm.SendProtocol(0x69); // RFReset
            //    readerStatus = fedm.SendProtocol(0xB0); // ISOCmd
            //    if (readerStatus != 0 && readerStatus != 0x94)
            //    {
            //        obj2 = readerStatus;
            //        result = BeginInvoke(NoTagMethod, obj2);
            //        EndInvoke(result);
            //        MessageBox.Show("No Tag");
            //        return "";
            //    }

            //    while (fedm.GetLastStatus() == 0x94) // more flag set?
            //    {
            //        fedm.SetData(FedmIscReaderID.FEDM_ISC_TMP_B0_MODE_MORE, 0x01);
            //        fedm.SendProtocol(0xB0);
            //    }
            //    //new dimensiion from array serialNumber,tagtype,SeNumbLength
            //    serialNumber = new string[fedm.GetTableLength(FedmIscReaderConst.ISO_TABLE)];
            //    tagType = new byte[fedm.GetTableLength(FedmIscReaderConst.ISO_TABLE)];

            //    if (fedm.GetTableLength(FedmIscReaderConst.ISO_TABLE) <= 0)
            //    {
            //        MessageBox.Show(" No Table");
            //        return "";
            //    }

            //    int i;
            //    for (i = 0; i < fedm.GetTableLength(FedmIscReaderConst.ISO_TABLE); i++)
            //    {
            //        fedm.GetTableData(i, FedmIscReaderConst.ISO_TABLE, FedmIscReaderConst.DATA_SNR, out serialNumber[i]);
            //        fedm.GetTableData(i, FedmIscReaderConst.ISO_TABLE, FedmIscReaderConst.DATA_TRTYPE, out tagType[i]);
            //        // check, wether UHF tags are available in list


            //    }
            //    //### Seriennummer
            //    obj1[0] = serialNumber;


            //    //asynchrone result senden
            //    result = BeginInvoke(TagChangedMethod, obj1);
            //    EndInvoke(result);


            //    return serialNumber[0];
            //}
            //catch (Exception ex)
            //{
            //    obj2 = ex.ToString();
            //    //asynchrone result senden
            //    result = BeginInvoke(LastErrorMethod, obj2);
            //    EndInvoke(result);
            //    running = false;
            //    return "";
            //}
        }

        public void StopReader()
        {

            // stop reading
            running = false;
            Prepared = true;
            //remove Events 
            fedm.RemoveEventListener(this, FeIscListenerConst.SEND_STRING_EVENT);
            fedm.RemoveEventListener(this, FeIscListenerConst.RECEIVE_STRING_EVENT);

            if (fedm.Connected == true)
            {
                // set Persistence Reset Time in Reader Configuration back to old value
                int back = OBID.Fedm.ERROR_UNSUPPORTED_NAMESPACE;
                try
                {
                    back = fedm.TestConfigPara(OBID.ReaderConfig.Transponder.PersistenceReset.Antenna.No1.PersistenceResetTime);
                }
                catch (Exception ex)
                { // ignore Exception
                }
                // if reader supports this parameter, set it back to old value !
                if (0 == back)
                {
                    try
                    {
                        back = fedm.SetConfigPara(OBID.ReaderConfig.Transponder.PersistenceReset.Antenna.No1.PersistenceResetTime, persistenceResetTime, false);
                        if (back == 1) // return value 1 indicates modified parameter
                            back = fedm.ApplyConfiguration(false);
                    }
                    catch (Exception ex)
                    {
                        MessageBox.Show( ex.ToString(), "Error");
                    }
                }
            }
        }

        /******************** Methode to show protocol*****************************/

        //show sent Protocol
        public void DisplaySendProtocol(string protocol)
        {
            //if (this.checkBoxEnable.Checked)
            //{
            //    this.textBoxProtocol.Text += protocol;
            //}
        }

        //show received protocol
        public void DisplayReceiveProtocol(string protocol)
        {
            //if (this.checkBoxEnable.Checked)
            //{
            //    this.textBoxProtocol.Text += protocol;
            //}
        }

        /********************************END****************************************/




        /*### 
         * Wenn Transponder-Suche gestoppt kann gelesen werden
         * 
         */
        private void Read()
        {
            byte[] data;
            byte blockSize;
            int idx;
            int dbn;
            int address;
            int mode;

            long datalocation = FedmIscReaderConst.DATA_RxDB;


            //   mode = 1;  Addressed Mode
            mode = Konstanten.mode; // this.comboBoxMod.SelectedIndex;

            //### Transponder-Tag auswählen
            //int selRow;
            //this.listBoxTags.SelectedIndex = 0;
            //Transponder-ID auswählen
            //selRow = this.listBoxTags.SelectedIndex;


            //if (selRow == -1 && mode > 0)
            //{
            //    MessageBox.Show(this, "There was no tag selected.", "Error");
            //    return;
            //}


            // set IscTable-Parameter - ### Was machen diese beiden??

            dbn = Konstanten.dbn; // (int)this.numericUpDownDBN.Value; //Anzahl zu lesender Blöcke
            address = Konstanten.address; // (int)this.numericUpDownAdr.Value; //Startblock, bei dem begonnen wird zu lesen

            fedm.SetData(FedmIscReaderID.FEDM_ISC_TMP_B0_MODE, (byte)0);
            fedm.SetData(FedmIscReaderID.FEDM_ISC_TMP_B0_REQ_UID, TransponderSerialNumber);
            fedm.SetData(FedmIscReaderID.FEDM_ISC_TMP_B0_CMD, 0x23);
            fedm.SetData(FedmIscReaderID.FEDM_ISC_TMP_B0_REQ_DBN, dbn);
            fedm.SetData(FedmIscReaderID.FEDM_ISC_TMP_B0_MODE_ADR, mode);



            fedm.SetData(FedmIscReaderID.FEDM_ISC_TMP_B0_REQ_DB_ADR, address);


            // Send ReadMultipleBlocks-Protocol - "Ausführen"
            try
            {
                fedm.SendProtocol(0xB0);
            }

            catch (System.Exception ex)
            {
                MessageBox.Show(ex.ToString(), "Error");
                return;
            }


            // idx  wegen Mode = 1 (Addressed)
            idx = fedm.FindTableIndex(0, FedmIscReaderConst.ISO_TABLE, FedmIscReaderConst.DATA_SNR, TransponderSerialNumber);


            // get blockSize from ISC-table, default = 4
            FedmIsoTableItem item;

            try
            {

                item = (FedmIsoTableItem)fedm.GetTableItem(idx, FedmIscReaderConst.ISO_TABLE);
                //Blocksize des Transponders auslesen
                item.GetData((FedmIscReaderConst.DATA_BLOCK_SIZE), out blockSize);
            }
            catch (System.Exception ex)
            {
                MessageBox.Show(ex.ToString(), "Error");
                return;
            }

            // Default-Wert für blockSize nehmen.
            if (blockSize == 0)
            {
                blockSize = 4; // default value
            }

            //set current blockSize (DB-Size)
            //this.numericUpDownDBS.Value = blockSize;

            //Set DataBlockData from ResponseBuffer to HexEdit
            int i;


            for (i = 0; i < dbn; i++)
            {

                //### data=byte[0]
                item.GetData(datalocation, address + i, out data);
                //##data in Array
                CustomerIDArray = data;
                //HexEdit.InsertData((address + i) * blockSize, data); //### Index, wert
            }
        }

    }
}
